Demos
This is a brief explanation of how to work with Liberty Basic menus, dynamically setting and resetting checkmarks. There is an accompanying program that shows the concepts in a fun and delicious way. It was created with Tom Nally specifically in mind, and I hope he enjoys it. This article comes as a result of a question asked on the Liberty Basic Conforum's site.
Menus are native to Liberty Basic. In fact in version 4 of the language, you can enable and disable menu items individually. However, placing a checkmark in front of a selected menu item (as is often done in option type menus) is not possible using LB native commands. For this we must use the Windows API.
There are four API calls required. Three of the API calls are used to obtain the handle and menu IDs to the menu items that the check marks will be applied to. We will look at these in depth in a minute. First lets examine the relationship of menu, submenu and window.

Notice in the example above that we have several objects:
In order to apply a checkmark or remove one, you must have the SubMenuItem ID. It is obtained by walking down the path from window, to menu, to submenu and finally to submenuitem. We use a series of API calls to do this:
GetMenu is the first - which returns the handle of the menu object container:
Function GetMenu(hWnd)
CallDLL #user32, "GetMenu",hWnd As Long,GetMenu As Long
End Function
Once that is known we can get an individual submenu ID using the GetSubMenu API call. The actual ID is returned by the API call as the result.
Function GetSubMenu(hMenuBar,nPos)
CallDLL #user32, "GetSubMenu",_
hMenuBar As Long, nPos As Long, GetSubMenu As Long
End Function
Using the submenu ID we can get an individual SubMenuItem ID. I like to get all the IDs of any submenuitem I will be setting a check mark for, and storeing them in an array. I will show that code in a moment. The API call GetMenuItemID is used to get this ID:
Function GetMenuItemID(hSubMenu,nPos)
CallDLL #user32, "GetMenuItemID", hSubMenu As Long, _
nPos As Long, GetMenuItemID As Long
End Function
Above each of the functions are encapsulated in functions which are courtesy of Alyce Watson and the fantastic Liberty Basic Workshop. I implemented these functions in the code of my demo program in the following way:
'** Get the main window handle
hWnd = hwnd(#main)
'** Get the menu handle for the menus
hMenu = GetMenu(hWnd)
'** Get the sub menu ID for the Skill Level menu only
'Menus are numbered from 0 up. Menu 1 is the second from left.
hSubMenu = GetSubMenu(hMenu,1)
'** Finally, get the menu ID's for the items on the Skill Level menu
'there are 10 of them, so I will use an array
for x = 0 to 9
menuID = GetMenuItemID(hSubMenu,x)
subMenuID(x) = menuID
next x
Once we have the SubMenuItemIDs we can set and reset the checkmark using the API call CheckMenuItem. Alyce actually implemented it in LB Workshop as a function. The API call returns a status indicating success and failure. I really did not care for the purpose of this demo, so I changed the function into a sub. You will probably want to use the function in your code if you are writing programs that will be released into the public, as it is good practice to trap all potential errors and handle them.
sub CheckMenuItem hSubMenu,menuid,wCheck
'Note: Alyce wrote this as a function, but I changed to a sub
'as a function it returns the status of the call, but that is
'not critical to my needs.
'wCheck 0=unchecked,8=checked
CallDLL #user32,"CheckMenuItem", hSubMenu As Long,_
menuid As Long, wCheck As Long, result As Long
End sub
In my implementation I only wanted one menu item checked at any given time, so I unchecked the current choice and check the new choice. This is not required, you can have any, all or even no menu items checked in your program.
I implemented the check marking component of my code as a function that receives the old (current) menu item index and the new choice. It looks up the actual SubMenuItemID from the array I built elsewhere. Here is the code:
function updatedonut(current, newpick, hSubMenu)
'first I want to uncheck the menu item that is current
call CheckMenuItem hSubMenu,subMenuID(current),0
'Next check the menu item that is the new pick
call CheckMenuItem hSubMenu,subMenuID(newpick),8
[snip]
'finally set the function to return the new current
updatedonut = newpick
end function
The demonstration program is simple, but entertaining. I would recommend not running it when you are hungry, or you will be jumping into your car and heading out to the closest KrispyKreme! You will find the program and its associated image files in an archive that is part of the newsletter download. You will need all the files to get the program to run. I have included the source code here for your viewing pleasure:
'** Created by LB Workshop (Functions/Subs courtesy Alyce Watson)
'** Donut Picker, by Brad Moore - 2004
'** Released into the Public Domain: July 31, 2004
dim subMenuID(10)
dim images$(10)
'load the images
for x = 0 to 10
read a$
images$(x) = a$
a$ = a$ + ".bmp"
loadbmp images$(x), a$
next x
NOMAINWIN
WindowWidth = 200 : WindowHeight = 200
UpperLeftX = INT((DisplayWidth-WindowWidth)/2)
UpperLeftY = INT((DisplayHeight-WindowHeight)/2)
'set up the controls and menus for our window
Menu #main, "File", "About", [about], | , "Exit", [quit]
Menu #main, "Donuts", "Glazed", [glazed], "Chocolate Glazed", [chocglaze],_
"Sugar Coated", [sugar], "Chocolate Sprinkle", [sprinkle], _
"Glazed Cruller", [cruller], "Chocolate Cruller", [choccruller], _
"Powedered Cake", [powder], "Dulce de Leche", [dulce], _
"Caramel Kreme Crunch", [caramel], "NY Cheese Crunch", [nycheese]
graphicbox #main.gb,-5,-5, 200, 155
Open "Donut Picker" for Window as #main
'final touches to the window
#main "trapclose [quit]"
#main.gb "down; fill White; flush"
#main "font ms_sans_serif 10"
#main.gb "up; goto 32 10;down; drawbmp kk; flush"
'-------------------------------------------------------------------------------
' Get the handles of the menus and submenus for management of check menu items
'** Get the main window handle
hWnd = hwnd(#main)
'** Get the menu handle for the menus
hMenu = GetMenu(hWnd)
'** Get the sub menu ID for the Skill Level menu only
'Menus are numbered from 0 up. Menu 1 is the second from left.
hSubMenu = GetSubMenu(hMenu,1)
'** Finally, get the menu ID's for the items on the Skill Level menu
'there are 10 of them, so I will use an array
for x = 0 to 9
menuID = GetMenuItemID(hSubMenu,x)
subMenuID(x) = menuID
next x
'The last item to do here is to check the current menu item and display the new graphic
'remember that menus are numbered from zero
current = 0
current = updatedonut(current, 0, hSubMenu)
[loop]
Wait
[quit]
close #main : END
[about]
a$ = "About Donut Picker" + chr$(13) + _
"Donut Picker was concieved as a demonstration program to show how to" + chr$(13) + _
"create checkmark menu options in Liberty Basic. This program borrows" + chr$(13) + _
"elements from many sources. Many of the functions and API calls are" + chr$(13) + _
"courtesy of Alyce Watson. Check out the many resourses at her web-" + chr$(13) + _
"site: http://alycesrestaurant.com."
notice a$
Wait
[glazed]
current = updatedonut(current, 0, hSubMenu)
Wait
[chocglaze]
current = updatedonut(current, 1, hSubMenu)
Wait
[sugar]
current = updatedonut(current, 2, hSubMenu)
Wait
[sprinkle]
current = updatedonut(current, 3, hSubMenu)
Wait
[cruller]
current = updatedonut(current, 4, hSubMenu)
Wait
[choccruller]
current = updatedonut(current, 5, hSubMenu)
Wait
[powder]
current = updatedonut(current, 6, hSubMenu)
Wait
[dulce]
current = updatedonut(current, 7, hSubMenu)
Wait
[caramel]
current = updatedonut(current, 8, hSubMenu)
Wait
[nycheese]
current = updatedonut(current, 9, hSubMenu)
Wait
'-----------------------------------------------------------------------------
' Data
data glazed, chocglaze, sugar, sprinkle, cruller, choccruller
data powder, dulce, caramel, nycheese, kk
'-----------------------------------------------------------------------------
' UpdateDonut sub program does the work of checking menus and
' displaying donut images
function updatedonut(current, newpick, hSubMenu)
'first I want to uncheck the menu item that is current
call CheckMenuItem hSubMenu,subMenuID(current),0
'Next check the menu item that is the new pick
call CheckMenuItem hSubMenu,subMenuID(newpick),8
'Now lets load the new image
#main.gb "delsegment donuts; color white; backcolor white"
#main.gb "up; goto 30 70; down; boxfilled 160 160"
'#main.gb "up; goto 58 70; down; drawbmp ";images$(newpick);" 58 70"
#main.gb "down; drawbmp ";images$(newpick);" 58 79"
#main.gb "flush donuts"
'finally set the function to return the new current
updatedonut = newpick
end function
'-----------------------------------------------------------------------------
'Functions: courtsey of Alyce Watson's LB Workshop API wrapper
'checkout LB Workshop at http://alycesrestaurant.com
Function GetMenuItemID(hSubMenu,nPos)
CallDLL #user32, "GetMenuItemID", hSubMenu As Long, _
nPos As Long, GetMenuItemID As Long
End Function
Function GetSubMenu(hMenuBar,nPos)
CallDLL #user32, "GetSubMenu",_
hMenuBar As Long, nPos As Long, GetSubMenu As Long
End Function
Function GetMenu(hWnd)
CallDLL #user32, "GetMenu",hWnd As Long,GetMenu As Long
End Function
sub CheckMenuItem hSubMenu,menuid,wCheck
'Note: Alyce wrote this as a function, but I changed to a sub
'as a function it returns the status of the call, but that is
'not critical to my needs.
'wCheck 0=unchecked,8=checked
CallDLL #user32,"CheckMenuItem", hSubMenu As Long,_
menuid As Long, wCheck As Long, result As Long
End sub
by Brad Moore - article copyright 2004. Program source in the public domain.